//
// Copyright (c) 2024 BPer
//
#ifndef BPERSOCKETUTIL_H_
#define BPERSOCKETUTIL_H_
#include <stdint.h>
#include <bperutil/sys/BPerVector.h>

#if BPer_OS_WIN
#include <winsock2.h>
#include <ws2tcpip.h>
#include <errno.h>
#define socklen_t int
#define bPer_be32toh ntohl
#define GetSockError()	WSAGetLastError()
#define SetSockError(e)	WSASetLastError(e)
#define setsockopt(a,b,c,d,e)	(setsockopt)(a,b,c,(const char *)d,(int)e)
#define BPER_NO_SIGNAL 0
#define bPer_poll WSAPoll
#else
#include <netinet/in.h>
#include <errno.h>
	#if BPer_OS_APPLE
		#include <TargetConditionals.h>
        #include <libkern/OSByteOrder.h>
        #define bPer_be32toh OSSwapBigToHostInt32
		#define BPER_NO_SIGNAL SO_NOSIGPIPE
	#else
        #define bPer_be32toh be32toh
		#define BPER_NO_SIGNAL MSG_NOSIGNAL
	#endif

#define bPer_poll poll
#define GetSockError()	errno
#define SetSockError(e)	errno = e
#endif

#define bPer_ntohl ntohl
#define bPer_htons htons
#define bPer_ntohs ntohs
#define bPer_inet_addr inet_addr
#define bPer_inet_pton inet_pton
#define bPer_inet_ntoa inet_ntoa


#define bPer_socket_t int
typedef struct sockaddr_in bPer_socket_addr4;
typedef struct sockaddr_in6 bPer_socket_addr6;


typedef struct {
    int32_t port;
    uint32_t mapAddress;
    BPerIpFamilyType familyType;
    BPerSocketProtocol protocol;

    uint8_t  address[16];
    bPer_socket_addr4 addr4;
    bPer_socket_addr6 addr6;

} BPerIpAddress;

#ifdef __cplusplus
extern "C"{
#endif

void bPer_addr_set(BPerIpAddress* addr,char* ip,int32_t port,BPerIpFamilyType familyType, BPerSocketProtocol protocol);
void bPer_addr_setAnyAddr(BPerIpAddress* addr,int32_t port,BPerIpFamilyType familyType, BPerSocketProtocol protocol);

void bPer_addr_setIPV4(BPerIpAddress* addr,int32_t ip,int32_t port,BPerSocketProtocol protocol);
void bPer_addr_setIPV6(BPerIpAddress* addr,uint8_t ip[16],int32_t port, BPerSocketProtocol protocol);
uint32_t bPer_addr_getIP(BPerIpAddress* addr);
void bPer_addr_getIPStr(BPerIpAddress* addr,char* addrstr,int32_t strLen);
uint16_t bPer_addr_getPort(BPerIpAddress* addr);
uint16_t bPer_addr_getSinPort(BPerIpAddress* addr);
bPer_socket_t bPer_socket_create(BPerIpFamilyType familyType, BPerSocketProtocol protocol);
//non-block socket
int32_t bPer_socket_setNonblock(bPer_socket_t fd);
int32_t bPer_socket_close(bPer_socket_t fd);

int32_t bPer_socket_listen(bPer_socket_t fd,BPerIpAddress* addr);

int32_t bPer_socket_connect(bPer_socket_t fd,BPerIpAddress* remoteAddr);
int32_t bPer_socket_recvfrom(bPer_socket_t fd,char* buffer,int32_t bufferLen,BPerIpAddress* addr);

int32_t bPer_socket_accept(bPer_socket_t fd,BPerIpAddress* addr);

int32_t bPer_socket_sendto(bPer_socket_t fd,char* data,int32_t nb,BPerIpAddress* remote_addr,int32_t flag);
int32_t bPer_socket_send(bPer_socket_t fd,char* data,int32_t nb);
int32_t bPer_socket_send2(bPer_socket_t fd,char* data,int32_t nb,int32_t flag);
int32_t bPer_socket_recv(bPer_socket_t fd,char* data,int32_t nb,int32_t flag);


int32_t bPer_getLocalInfo(BPerIpFamilyType familyType,char* p);
int32_t bPer_getLocalInfoList(BPerIpFamilyType familyType,BPerStringVector* p);
int32_t bPer_getIp(BPerIpFamilyType familyType, char* domain, char* ip);

#ifdef __cplusplus
}
#endif
#endif /* BPERSOCKETUTIL_H_ */
